package com.neusoft.neuiotms.sap;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.neusoft.bizcore.activiti.enums.WorkOrderStatus;
import com.neusoft.bizcore.activiti.repository.WorkOrderRepository;
import com.neusoft.bizcore.web.dto.result.ResultDTO;
import com.neusoft.bizcore.web.dto.result.ResultListDTO;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcom.dto.InstitutionsDTO;
import com.neusoft.neuiotms.dcom.dto.ProjectDTO;
import com.neusoft.neuiotms.dcom.model.Institutions;
import com.neusoft.neuiotms.dcom.model.enums.HnInspectionTaskStatus;
import com.neusoft.neuiotms.dcom.model.hn.HnInspectionTask;
import com.neusoft.neuiotms.dcom.repository.InstitutionsRepository;
import com.neusoft.neuiotms.dcom.repository.WorkDailyRepository;
import com.neusoft.neuiotms.dcom.repository.hn.HnInspectionHealthTaskRepository;
import com.neusoft.neuiotms.dcom.repository.hn.HnInspectionTaskRepository;
import com.neusoft.neuiotms.dcom.service.InstitutionsService;
import com.neusoft.neuiotms.dcom.service.ProjectService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@Api(tags = "大屏PAI")
@RestController
@RequestMapping(value = "/api/w/leader")
public class LeaderScreenController {

    @Autowired
    private ProjectService projectService;
    @Autowired
    private InstitutionsRepository institutionsRepository;
    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private WorkDailyRepository workDailyRepository;
    @Autowired
    private WorkOrderRepository workOrderRepository;
    @Autowired
    private HnInspectionTaskRepository hnInspectionTaskRepository;
    @Autowired
    private HnInspectionHealthTaskRepository hnInspectionHealthTaskRepository;
    //    @Autowired
    //    private MalfunctionService malfunctionService;
    @PersistenceContext
    private EntityManager entityManager;
    @Autowired
    private InstitutionsService institutionsService;

    @ApiOperation("服务概览")
    @GetMapping("/service/summary")
    //@Cacheable(value = "leaderServiceSummary")
    public ResultDTO<?> serviceSummary() {
        final ProjectDTO project = this.projectService.getInfoByCode("HN");
        final Date today = DateUtils.ceiling(new Date(), Calendar.DAY_OF_MONTH);
        final Date startDate = DateUtils.ceiling(project.getStartTime(), Calendar.DAY_OF_MONTH);
        final long serviceDayCount = (today.getTime() - startDate.getTime()) / 86400000;
        final long instCount = this.institutionsRepository.count();
        final long assetCount = this.assetRepository.count();
        final Double totalServiceHours = (this.workDailyRepository.totalServiceTime(new Searchable()) / 60.0);
        final long totalServiceTime = totalServiceHours.longValue();
        final long totalServiceCount = this.workDailyRepository.count();
        final Map<String, Long> result = Maps.newHashMap();
        result.put("serviceDayCount", serviceDayCount);
        result.put("instCount", instCount);
        result.put("assetCount", assetCount);
        result.put("totalServiceTime", totalServiceTime);
        result.put("totalServiceCount", totalServiceCount);

        return ResultDTO.success(result);
    }

    @ApiOperation("故障处理概览")
    @GetMapping("/malfunction/summary")
    //@Cacheable(value = "leaderMalfunctionSummary")
    public ResultDTO<?> malfunctionSummary() {

        final Map<String, Long> result = Maps.newHashMap();
        final Searchable query1 = new Searchable();
        query1.put("type", "malfunction");
        query1.put("statusArray", Lists.newArrayList(WorkOrderStatus.running));
        final long processingCount = this.workOrderRepository.count(query1);
        result.put("processingCount", processingCount);

        final Searchable query2 = new Searchable();
        query2.put("statusArray", Lists.newArrayList(WorkOrderStatus.finish));

        final Date now = new Date();
        query2.put("type", "malfunction");
        query2.put("beforeUpdateAt", now.getTime());
        final Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 1, 0, 0, 0);
        query2.put("afterUpdateAt", cal.getTimeInMillis());
        final long monthFinishedCount = this.workOrderRepository.count(query2);
        result.put("monthFinishedCount", monthFinishedCount);
        return ResultDTO.success(result);
    }

    @ApiOperation("巡检服务概览")
    @GetMapping("/inspection/summary")
    public ResultDTO<?> inspectionSummary() {

        final Map<String, Long> result = Maps.newHashMap();
        final Searchable query1 = new Searchable();
        query1.put("status", "finished");
        final long dailyInspectionCount = this.hnInspectionTaskRepository.count(query1);
        result.put("dailyInspectionCount", dailyInspectionCount);

        query1.put("itemStatus", "normal");
        final long dailyInspectionNormalCount = this.hnInspectionTaskRepository.count(query1);
        result.put("dailyInspectionNormalCount", dailyInspectionNormalCount);

        final Searchable query2 = new Searchable();
        query2.put("status", "finished");
        final long healthInspectionCount = this.hnInspectionHealthTaskRepository.count(query2);
        result.put("healthInspectionCount", healthInspectionCount);

        query2.put("itemStatus", "normal");
        final long healthInspectionNormalCount = this.hnInspectionHealthTaskRepository.count(query2);
        result.put("healthInspectionNormalCount", healthInspectionNormalCount);
        return ResultDTO.success(result);
    }

    @ApiOperation("资产在线状态")
    @GetMapping("/asset/summary")
    public ResultDTO<?> assetSummary() {

        final long assetCount = this.assetRepository.count();

        final Map<String, Long> result = Maps.newHashMap();
        long onlineCount = 0;
        long totalCount = 0;
        final List<Institutions> institutions = this.institutionsRepository.findAll();
        for (final Institutions inst : institutions) {
            final HnInspectionTask task =
                    this.hnInspectionTaskRepository.findFirstByInstitutionCodeAndStatusOrderByUpdateTimeDesc(
                            inst.getCode(), HnInspectionTaskStatus.finished);
            if (null != task) {
                totalCount += task.getAssets().size();
                onlineCount += task.getOnlineCount();
            }
        }
        final long offlineCount = totalCount - onlineCount;
        result.put("onlineCount", assetCount - offlineCount);
        result.put("offlineCount", offlineCount);

        return ResultDTO.success(result);
    }

    @SuppressWarnings("unchecked")
    @ApiOperation("故障服务统计")
    @GetMapping("/malfunction/stats")
    public ResultListDTO<?> malfunctionStats() {

        final String sql = " SELECT "
                + "     service_type_name as name, "
                + "     count(*) AS value "
                + " FROM "
                + "     neuiot_work_daily "
                + " WHERE "
                + "     service_type_name <> '' "
                + " GROUP BY "
                + "     service_type_name ";

        //        final List<String> metrics = Lists.newArrayList("a01_count", "a02_count", "a03_count", "a04_count", "a05_count",
        //                "a06_count", "a07_count", "a08_count", "a09_count");

        final Query query = this.entityManager.createNativeQuery(sql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        final List<Map<String, Object>> result = query.getResultList();
        //
        //        final Map<String, Integer> item = Maps.newHashMap();
        //        metrics.forEach(it -> {
        //            item.put(it, 0);
        //        });
        //
        //        final Map<String, Object> params = Maps.newHashMap();
        //        final List<Map<String, Object>> results = this.malfunctionService.report(params);
        //
        //        results.stream().forEach(it -> {
        //            metrics.stream().forEach(m -> {
        //                final int c = ((BigInteger) it.get(m)).intValue();
        //                item.put(m, item.get(m) + c);
        //            });
        //        });
        return ResultListDTO.success(result);
    }

    @SuppressWarnings("unchecked")
    @ApiOperation("资产数量TOP5")
    @GetMapping("/asset/top5")
    public ResultListDTO<?> assetTop5() {
        final String sql = "select code, name, count from ("
                + "select submmit_to, count(*) as count from neuiot_fixed_asset group by submmit_to order by count desc limit 5"
                + ") t0 left join neuiot_institutions t1 on t0.submmit_to = t1.name";
        final Query query = this.entityManager.createNativeQuery(sql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        final List<Map<String, Object>> result = query.getResultList();
        for (final Map<String, Object> map : result) {
            final String instCode = (String) map.get("code");
            final HnInspectionTask task =
                    this.hnInspectionTaskRepository.findFirstByInstitutionCodeAndStatusOrderByUpdateTimeDesc(
                            instCode, HnInspectionTaskStatus.finished);
            map.put("online", null != task ? task.getOnlineCount() : 0);
        }

        return ResultListDTO.success(result);
    }

    @SuppressWarnings("unchecked")
    @ApiOperation("在线资产变化趋势")
    @GetMapping("/asset/trend")
    public ResultListDTO<?> assetTrend() {
        final Date now = new Date();
        final Date from = new Date(DateUtils.round(now, Calendar.DAY_OF_MONTH).getTime() - (86400000 * 7));
        final String fromStr = DateFormatUtils.format(from, "yyyy-MM-dd");
        final String endStr = DateFormatUtils.format(DateUtils.round(now, Calendar.DAY_OF_MONTH), "yyyy-MM-dd");
        final List<String> dateArray = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7).stream().map(i -> {
            return DateFormatUtils.format(
                    new Date(DateUtils.round(now, Calendar.DAY_OF_MONTH).getTime() - (86400000 * i)), "yyyy-MM-dd");
        }).collect(Collectors.toList());
        final String sql = "select date, count(*) count from "
                + "( "
                + "select DATE_FORMAT(t0.start_date_time,'%Y-%m-%d') as date, t1.online from neuiot_inspection_task_hn t0 "
                + "left join neuiot_inspection_task_asset_hn t1 on t0.id = t1.task_id "
                + "where  t1.online = 1 and start_date_time > '" + fromStr + "' and start_date_time < '" + endStr + "' "
                + "order by start_date_time asc "
                + ") t0  "
                + "group by t0.date, t0.online;";

        final Query query = this.entityManager.createNativeQuery(sql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);

        final List<Map<String, Object>> result = query.getResultList();

        dateArray.stream().forEach(d -> {
            if (!result.stream().filter(it -> it.containsValue(d)).findAny().isPresent()) {
                final Map<String, Object> item = new HashedMap<>();
                item.put("date", d);
                item.put("count", 0);
                result.add(item);
            }
        });

        return ResultListDTO.success(result);
    }

    @SuppressWarnings("unchecked")
    @ApiOperation("地图展示")
    @GetMapping("/institute/summery")
    public ResultListDTO<?> instituteSummary() {
        final List<Map<String, Object>> results = Lists.newArrayList();

        final String malSql =
                "SELECT t1.service_unit_code,t1.service_unit_name,count(1) AS count FROM wf_work_order t0 "
                        + "LEFT JOIN neuiot_malfunction_apply_form t1 ON t0.work_order_num = t1.work_num where t0.status = 'finish' "
                        + "GROUP BY t1.service_unit_code,t1.service_unit_name ";
        final Query query = this.entityManager.createNativeQuery(malSql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        final List<Map<String, Object>> malfunctions = query.getResultList();

        final List<Institutions> allInsts = this.institutionsRepository.findAll();
        for (final Institutions inst : allInsts) {
            final Map<String, Object> result = Maps.newHashMap();
            result.put("name", inst.getName());
            result.put("lng", inst.getLng());
            result.put("lat", inst.getLat());
            final HnInspectionTask latestTask =
                    this.hnInspectionTaskRepository.findFirstByInstitutionCodeAndStatusOrderByUpdateTimeDesc(
                            inst.getCode(), HnInspectionTaskStatus.finished);
            if (null != latestTask) {
                result.put("status", latestTask.getItemStatus().toString());
            } else {
                result.put("status", "uninspected");
            }

            final Optional<Map<String, Object>> malfunction = malfunctions.stream()
                    .filter(mal -> inst.getCode().equals(mal.get("service_unit_code"))).findFirst();

            if (malfunction.isPresent()) {
                result.put("malfunction", malfunction.get().get("count"));
            } else {
                result.put("malfunction", 0);
            }

            result.put("residents", inst.getResidents().size());

            results.add(result);

        }

        return ResultListDTO.success(results);
    }

    @ApiOperation("查询所有单位")
    @GetMapping("/institutions")
    public ResultListDTO<InstitutionsDTO> index(final Searchable searchable) {
        return ResultListDTO.success(this.institutionsService.index(searchable));
    }

}
